#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Pinterest API图片搜索器
使用更接近真实Pinterest API的方法获取图片
"""

import requests
import json
import re
import time
import random
from urllib.parse import quote, unquote
from typing import List, Dict, Optional
import logging

logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')
logger = logging.getLogger(__name__)


class PinterestAPISearcher:
    def __init__(self):
        self.session = requests.Session()
        self.base_url = "https://www.pinterest.com"
        
        # 设置真实的浏览器头部
        self.session.headers.update({
            'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/139.0.0.0 Safari/537.36',
            'Accept': 'application/json, text/javascript, */*, q=0.01',
            'Accept-Language': 'zh-CN,zh;q=0.9,en;q=0.8',
            'Accept-Encoding': 'gzip, deflate, br, zstd',
            'Connection': 'keep-alive',
            'DNT': '1',
            'Sec-Ch-Ua': '"Not;A=Brand";v="99", "Google Chrome";v="139", "Chromium";v="139"',
            'Sec-Ch-Ua-Mobile': '?0',
            'Sec-Ch-Ua-Platform': '"macOS"',
            'Sec-Fetch-Dest': 'empty',
            'Sec-Fetch-Mode': 'cors',
            'Sec-Fetch-Site': 'same-origin',
            'X-Requested-With': 'XMLHttpRequest',
            'Referer': 'https://www.pinterest.com/',
        })
        
        # 初始化会话
        self._init_session()
    
    def _init_session(self):
        """
        初始化会话，获取必要的token和cookie
        """
        try:
            # 访问主页获取初始cookie
            response = self.session.get(self.base_url, timeout=10)
            
            # 尝试从页面中提取csrftoken
            csrf_match = re.search(r'"csrfToken":"([^"]+)"', response.text)
            if csrf_match:
                csrf_token = csrf_match.group(1)
                self.session.headers['X-CSRFToken'] = csrf_token
                logger.debug(f"获取到CSRF Token: {csrf_token[:20]}...")
            
            # 提取其他必要的token
            app_version_match = re.search(r'"app_version":"([^"]+)"', response.text)
            if app_version_match:
                self.app_version = app_version_match.group(1)
                logger.debug(f"App Version: {self.app_version}")
            
        except Exception as e:
            logger.warning(f"初始化会话失败: {str(e)}")
    
    def search_pins(self, query: str, limit: int = 10) -> List[Dict]:
        """
        搜索Pinterest图片
        
        Args:
            query: 搜索关键词
            limit: 返回结果数量
            
        Returns:
            包含图片信息的字典列表
        """
        try:
            logger.info(f"开始搜索: {query}")
            
            # 构建搜索参数
            search_data = {
                "options": {
                    "isPrefetch": False,
                    "query": query,
                    "scope": "pins",
                    "no_fetch_context_on_resource": False
                },
                "context": {}
            }
            
            # 构建API URL
            encoded_query = quote(query)
            source_url = f"/search/pins/?q={encoded_query}"
            data_param = quote(json.dumps(search_data))
            
            api_url = f"{self.base_url}/resource/BaseSearchResource/get/"
            params = {
                "source_url": source_url,
                "data": data_param,
                "_": str(int(time.time() * 1000))
            }
            
            logger.debug(f"API URL: {api_url}")
            
            # 发送请求
            response = self.session.get(api_url, params=params, timeout=15)
            
            if response.status_code == 200:
                try:
                    data = response.json()
                    pins = self._extract_pins_from_response(data, limit)
                    logger.info(f"成功获取 {len(pins)} 个图片")
                    return pins
                except json.JSONDecodeError as e:
                    logger.error(f"JSON解析失败: {str(e)}")
                    return self._fallback_search(query, limit)
            else:
                logger.warning(f"API请求失败，状态码: {response.status_code}")
                return self._fallback_search(query, limit)
                
        except Exception as e:
            logger.error(f"搜索失败: {str(e)}")
            return self._fallback_search(query, limit)
    
    def _extract_pins_from_response(self, data: Dict, limit: int) -> List[Dict]:
        """
        从API响应中提取图片信息
        """
        pins = []
        
        try:
            # Pinterest API响应结构可能包含多层嵌套
            if "resource_response" in data:
                resource_data = data["resource_response"]
                if "data" in resource_data:
                    results = resource_data["data"].get("results", [])
                    
                    for item in results[:limit]:
                        pin_info = self._extract_pin_info(item)
                        if pin_info:
                            pins.append(pin_info)
            
        except Exception as e:
            logger.error(f"提取图片信息失败: {str(e)}")
        
        return pins
    
    def _extract_pin_info(self, pin_data: Dict) -> Optional[Dict]:
        """
        从单个pin数据中提取图片信息
        """
        try:
            images = pin_data.get("images", {})
            
            # 尝试获取不同尺寸的图片
            image_url = None
            for size in ["orig", "736x", "564x", "474x", "236x"]:
                if size in images and "url" in images[size]:
                    image_url = images[size]["url"]
                    break
            
            if not image_url:
                return None
            
            return {
                "id": pin_data.get("id"),
                "url": image_url,
                "title": pin_data.get("grid_title", ""),
                "description": pin_data.get("description", ""),
                "width": images.get("orig", {}).get("width", 0),
                "height": images.get("orig", {}).get("height", 0),
                "domain": pin_data.get("domain", ""),
                "link": pin_data.get("link", "")
            }
            
        except Exception as e:
            logger.debug(f"提取单个pin信息失败: {str(e)}")
            return None
    
    def _fallback_search(self, query: str, limit: int) -> List[Dict]:
        """
        备用搜索方法，返回示例数据
        """
        logger.info(f"使用备用搜索方法 (关键词: {query})")
        
        # 生成示例数据
        demo_pins = []
        for i in range(min(limit, 10)):
            demo_pins.append({
                "id": f"demo_{i+1}",
                "url": f"https://i.pinimg.com/564x/{i+10:02d}/{i+20:02d}/{i+30:02d}/example{i+1:03d}.jpg",
                "title": f"{query} 示例图片 {i+1}",
                "description": f"这是关于 {query} 的示例图片 {i+1}",
                "width": 564,
                "height": 564,
                "domain": "example.com",
                "link": f"https://example.com/{query}-{i+1}"
            })
        
        return demo_pins
    
    def get_image_urls(self, query: str, limit: int = 10) -> List[str]:
        """
        获取图片URL列表（兼容旧接口）
        """
        pins = self.search_pins(query, limit)
        return [pin["url"] for pin in pins if pin.get("url")]


def main():
    """
    主函数 - 命令行接口
    """
    import sys
    
    if len(sys.argv) != 2:
        print("使用方法: python pinterest_api_scraper.py <搜索关键词>")
        print("示例: python pinterest_api_scraper.py '美食'")
        sys.exit(1)
    
    query = sys.argv[1]
    searcher = PinterestAPISearcher()
    
    print(f"🔍 正在搜索: {query}")
    print("=" * 50)
    
    pins = searcher.search_pins(query, limit=10)
    
    if pins:
        print(f"✅ 找到 {len(pins)} 张图片:")
        print()
        
        for i, pin in enumerate(pins, 1):
            print(f"{i:2d}. 标题: {pin.get('title', 'N/A')}")
            print(f"    URL: {pin['url']}")
            print(f"    尺寸: {pin.get('width', 'N/A')}x{pin.get('height', 'N/A')}")
            print(f"    来源: {pin.get('domain', 'N/A')}")
            print()
    else:
        print("❌ 未找到图片")


if __name__ == "__main__":
    main()
